
#include <stdio.h>
#include <string.h>

#include "els_vm.h"
#include "catch.h"
#include "els_vm_bytecode.h"
#include "els.h"
#define NEW_CERROR (sizeof(ElsVmFallBackSitu) / sizeof(struct _CERROR))

Object *lockArray = NULL;
Word lockSize = 0;
void error_CERROR(void);
void index_CERROR(void);
void getunit_CERROR(void);
void arith_CERROR(void);
void concat_CERROR(void);
void order_CERROR(void);
void GD_CERROR(void);
void func_CERROR(void);

struct _CERROR ElsVmFallBackSitu[] = {
    {"error", {ELS_TYPE_CERRORPI, {error_CERROR}}, 1, 0},
    {"index", {ELS_TYPE_CERRORPI, {index_CERROR}}, 2, 1},
    {"getunit", {ELS_TYPE_CERRORPI, {getunit_CERROR}}, 2, 1},
    {"arith", {ELS_TYPE_CERRORPI, {arith_CERROR}}, 3, 1},
    {"order", {ELS_TYPE_CERRORPI, {order_CERROR}}, 3, 1},
    {"concat", {ELS_TYPE_CERRORPI, {concat_CERROR}}, 2, 1},
    {"setunit", {ELS_TYPE_CERRORPI, {getunit_CERROR}}, 3, 0},
    {"gc", {ELS_TYPE_CERRORPI, {GD_CERROR}}, 1, 0},
    {"function", {ELS_TYPE_CERRORPI, {func_CERROR}}, -1, -1}};

void error_CERROR(void)
{
    els_Typesystem_Object o = els_getstack(1);
    if (els_isstr(o))
        printf("els: %s\n", els_getstr(o));
    else
        printf("els: unknown error\n");
}

void index_CERROR(void)
{
    els_pushnull();
}

void getunit_CERROR(void)
{
    els_error("索引表达式不是单位类型");
}

void arith_CERROR(void)
{
    els_error("转换为数值时类型发生错误");
}

void concat_CERROR(void)
{
    els_error("转换为字符串时类型发生错误");
}

void order_CERROR(void)
{
    els_error("比较的类型不符合要求");
}

void GD_CERROR(void) {}

void func_CERROR(void)
{
    els_error("调用的表达式不是函数");
}

int els_vm_lock(Object *object)
{
    Word i;
    Word oldSize;
    if (tag(object) == ELS_TYPE_NULL)
        return -1;
    for (i = 0; i < lockSize; i++)
        if (tag(&lockArray[i]) == ELS_TYPE_NULL)
        {
            lockArray[i] = *object;
            return i;
        }
    /* no more empty spaces ，it will call a fallback and SG*/
    oldSize = lockSize;
    if (lockArray == NULL)
    {
        lockSize = 10;
        lockArray = newvector(lockSize, Object);
    }
    else
    {
        lockSize = 3 * oldSize / 2 + 5;
        lockArray = growvector(lockArray, lockSize, Object);
    }
    for (i = oldSize; i < lockSize; i++)
        tag(&lockArray[i]) = ELS_TYPE_NULL;
    lockArray[oldSize] = *object;
    return oldSize;
}

void els_unlock(int ref)
{
    tag(&lockArray[ref]) = ELS_TYPE_NULL;
}

Object *els_vm_getlocked(int ref)
{
    return &lockArray[ref];
}

void els_vm_travlock(int (*fn)(Object *))
{
    Word i;
    for (i = 0; i < lockSize; i++)
        fn(&lockArray[i]);
}

char *els_vm_travfallbacks(int (*fn)(Object *))
{
    Word i;
    for (i = 0; i < NEW_CERROR; i++)
        if (fn(&ElsVmFallBackSitu[i].function))
            return ElsVmFallBackSitu[i].kind;
    return NULL;
}
